library(mosaic)
library(tidyverse)
library(lubridate)
library(DataComputing)
library(rvest)
library(broom)

Research Focus:

As COVID-19 spreads at an alarming rate, a pressing question at a global scale emerges– what factors of a country contribute to the spread of Coronavirus. We hope to analyze the relationship between a country’s population level, population density, and continent categorization on the spread of COVID-19.

Data Access

Reading in the Data:

Data Source 1: COVID

COVID <- read.csv(file = "total-covid-cases-deaths-per-million.csv")
COVID
COVID %>%
  nrow()
[1] 9487
COVID %>%
  names()
  [1] "total.covid.cases.deaths.per.million" "X"                                   
  [3] "X.1"                                  "X.2"                                 
  [5] "X.3"                                  "X.4"                                 
  [7] "X.5"                                  "X.6"                                 
  [9] "X.7"                                  "X.8"                                 
 [11] "X.9"                                  "X.10"                                
 [13] "X.11"                                 "X.12"                                
 [15] "X.13"                                 "X.14"                                
 [17] "X.15"                                 "X.16"                                
 [19] "X.17"                                 "X.18"                                
 [21] "X.19"                                 "X.20"                                
 [23] "X.21"                                 "X.22"                                
 [25] "X.23"                                 "X.24"                                
 [27] "X.25"                                 "X.26"                                
 [29] "X.27"                                 "X.28"                                
 [31] "X.29"                                 "X.30"                                
 [33] "X.31"                                 "X.32"                                
 [35] "X.33"                                 "X.34"                                
 [37] "X.35"                                 "X.36"                                
 [39] "X.37"                                 "X.38"                                
 [41] "X.39"                                 "X.40"                                
 [43] "X.41"                                 "X.42"                                
 [45] "X.43"                                 "X.44"                                
 [47] "X.45"                                 "X.46"                                
 [49] "X.47"                                 "X.48"                                
 [51] "X.49"                                 "X.50"                                
 [53] "X.51"                                 "X.52"                                
 [55] "X.53"                                 "X.54"                                
 [57] "X.55"                                 "X.56"                                
 [59] "X.57"                                 "X.58"                                
 [61] "X.59"                                 "X.60"                                
 [63] "X.61"                                 "X.62"                                
 [65] "X.63"                                 "X.64"                                
 [67] "X.65"                                 "X.66"                                
 [69] "X.67"                                 "X.68"                                
 [71] "X.69"                                 "X.70"                                
 [73] "X.71"                                 "X.72"                                
 [75] "X.73"                                 "X.74"                                
 [77] "X.75"                                 "X.76"                                
 [79] "X.77"                                 "X.78"                                
 [81] "X.79"                                 "X.80"                                
 [83] "X.81"                                 "X.82"                                
 [85] "X.83"                                 "X.84"                                
 [87] "X.85"                                 "X.86"                                
 [89] "X.87"                                 "X.88"                                
 [91] "X.89"                                 "X.90"                                
 [93] "X.91"                                 "X.92"                                
 [95] "X.93"                                 "X.94"                                
 [97] "X.95"                                 "X.96"                                
 [99] "X.97"                                 "X.98"                                
[101] "X.99"                                 "X.100"                               
[103] "X.101"                                "X.102"                               
[105] "X.103"                                "X.104"                               
[107] "X.105"                                "X.106"                               
[109] "X.107"                                "X.108"                               
[111] "X.109"                                "X.110"                               
[113] "X.111"                                "X.112"                               
[115] "X.113"                                "X.114"                               
[117] "X.115"                                "X.116"                               
[119] "X.117"                                "X.118"                               
[121] "X.119"                                "X.120"                               
[123] "X.121"                                "X.122"                               
[125] "X.123"                                "X.124"                               
[127] "X.125"                                "X.126"                               
[129] "X.127"                                "X.128"                               
[131] "X.129"                                "X.130"                               
[133] "X.131"                                "X.132"                               
[135] "X.133"                                "X.134"                               
[137] "X.135"                                "X.136"                               
[139] "X.137"                                "X.138"                               
[141] "X.139"                                "X.140"                               
[143] "X.141"                                "X.142"                               
[145] "X.143"                                "X.144"                               
[147] "X.145"                                "X.146"                               
[149] "X.147"                                "X.148"                               
[151] "X.149"                                "X.150"                               
[153] "X.151"                                "X.152"                               
[155] "X.153"                                "X.154"                               
[157] "X.155"                                "X.156"                               
[159] "X.157"                                "X.158"                               
[161] "X.159"                                "X.160"                               
[163] "X.161"                                "X.162"                               
[165] "X.163"                                "X.164"                               
[167] "X.165"                                "X.166"                               
[169] "X.167"                                "X.168"                               
[171] "X.169"                                "X.170"                               
[173] "X.171"                                "X.172"                               
[175] "X.173"                                "X.174"                               
[177] "X.175"                                "X.176"                               
[179] "X.177"                                "X.178"                               
[181] "X.179"                                "X.180"                               
[183] "X.181"                                "X.182"                               
[185] "X.183"                                "X.184"                               
[187] "X.185"                                "X.186"                               
[189] "X.187"                                "X.188"                               
[191] "X.189"                                "X.190"                               
[193] "X.191"                                "X.192"                               
[195] "X.193"                                "X.194"                               
[197] "X.195"                                "X.196"                               
[199] "X.197"                                "X.198"                               
[201] "X.199"                                "X.200"                               
[203] "X.201"                                "X.202"                               
[205] "X.203"                                "X.204"                               
[207] "X.205"                                "X.206"                               
[209] "X.207"                                "X.208"                               
[211] "X.209"                                "X.210"                               
[213] "X.211"                                "X.212"                               
[215] "X.213"                                "X.214"                               
[217] "X.215"                                "X.216"                               
[219] "X.217"                                "X.218"                               
[221] "X.219"                                "X.220"                               
[223] "X.221"                                "X.222"                               
[225] "X.223"                                "X.224"                               
[227] "X.225"                                "X.226"                               
[229] "X.227"                                "X.228"                               
[231] "X.229"                                "X.230"                               
[233] "X.231"                                "X.232"                               
[235] "X.233"                                "X.234"                               
[237] "X.235"                                "X.236"                               
[239] "X.237"                                "X.238"                               
[241] "X.239"                                "X.240"                               
[243] "X.241"                                "X.242"                               
[245] "X.243"                                "X.244"                               
[247] "X.245"                                "X.246"                               
[249] "X.247"                                "X.248"                               
[251] "X.249"                                "X.250"                               
[253] "X.251"                                "X.252"                               
[255] "X.253"                                "X.254"                               
COVID %>%
  head()

Data Source 2: CountryData

CountryData
CountryData %>%
  nrow()
[1] 256
CountryData %>%
  names()
 [1] "country"           "area"              "pop"               "growth"           
 [5] "birth"             "death"             "migr"              "maternal"         
 [9] "infant"            "life"              "fert"              "health"           
[13] "HIVrate"           "HIVpeople"         "HIVdeath"          "obesity"          
[17] "underweight"       "educ"              "unemploymentYouth" "GDP"              
[21] "GDPgrowth"         "GDPcapita"         "saving"            "indProd"          
[25] "labor"             "unemployment"      "family"            "tax"              
[29] "budget"            "debt"              "inflation"         "discount"         
[33] "lending"           "narrow"            "broad"             "credit"           
[37] "shares"            "balance"           "exports"           "imports"          
[41] "gold"              "externalDebt"      "homeStock"         "abroadStock"      
[45] "elecProd"          "elecCons"          "elecExp"           "elecImp"          
[49] "elecCap"           "elecFossil"        "elecNuc"           "elecHydro"        
[53] "elecRenew"         "oilProd"           "oilExp"            "oilImp"           
[57] "oilRes"            "petroProd"         "petroCons"         "petroExp"         
[61] "petroImp"          "gasProd"           "gasCons"           "gasExp"           
[65] "gasImp"            "gasRes"            "mainlines"         "cell"             
[69] "netHosts"          "netUsers"          "airports"          "railways"         
[73] "roadways"          "waterways"         "marine"            "military"         
CountryData %>%
  head()

Data Source 3: countryRegions

countryRegions
Error: object 'countryRegions' not found

rr countryRegions %>% nrow()

[1] 254

rr countryRegions %>% names()

 [1] \ISO3\         \ADMIN\        \REGION\       \continent\    \GEO3major\    \GEO3\         \IMAGE24\      \GLOCAF\      
 [9] \Stern\        \SRESmajor\    \SRES\         \GBD\          \AVOIDnumeric\ \AVOIDname\    \LDC\          \SID\         
[17] \LLDC\        

rr countryRegions %>% head()

Data Wrangling

Tidying the COVID Dataset

rr COVID

Since our analysis is focused on the spread of COVID-19, we select only columns which pertain to the number of COVID-19 cases in countries over time.

rr TidyCOVID <- COVID %>% rename(country = total.covid.cases.deaths.per.million ) %>% rename( Code = X ) %>% rename(date = X.1 ) %>% rename(casesPerMillion = X.3) %>% filter(row_number() > 1) %>% subset(select = c(1,2,3,5)) %>% mutate( country = as.character(country) ) %>% mutate(date = mdy(date)) %>% mutate(casesPerMillion = as.integer(casesPerMillion) - 1)

rr TidyCOVID

EVELYN pls explain what an instance represents

Wrangling of countryRegions Dataset

We will extract the ISO3 country code and continent from the countryRegions data. Since naming conventions of countries is variate, the ISO3 country code allows us a standardized demarcation of country with which to join with other data tables.

rr Labels <- countryRegions %>% subset(select = c(3, )) %>% rename(continent = REGION) Labels

Data Extraction of CountryData Dataset

We will select the aspects of CountryData relevant to our analysis. These attributes are: area (sq km) and pop (number of people).

rr RelevantCountryData <- CountryData %>% subset(select = c(1,2,3)) %>% mutate(popdensity = pop/area) RelevantCountryData

Joining Data & Relevant Variable Synthesis

Calculate the number of cases in each country by multiplying casesPerMillion by the country’s population (in millions).

rr COVIDGrowth <- inner_join(TidyCOVID, RelevantCountryData, by = c()) %>% mutate( = (casesPerMillion * round(pop/1000000, digits = 0))) COVIDGrowth <- COVIDGrowth %>% left_join(Labels, by = c( = 3))

Column `Code`/`ISO3` joining factor and character vector, coercing into character vector

rr COVIDGrowth

Creation of new Data Table: FirstInstance

This table records the first date that a country recorded a nonzero number of COVID-19 cases. This datagraph will help us visualize when countries first became infected.

rr FirstInstance <- COVIDGrowth %>% filter(cases != 0) %>% group_by(country, continent) %>% summarise(beginningofspread = min(date))

FirstInstance

This table averages the number of case increase per day from the first day a country had COVID-19 to the most recent in the data table (April 5 2020)

rr DailySpread <- left_join(COVIDGrowth, FirstInstance, by = c()) %>% filter(date == \2020-04-05) %>% mutate(dayselapsed = date - beginningofspread) %>% mutate(dailyspread = cases / as.numeric(dayselapsed) ) %>% mutate(dailyspreadpermillion = casesPerMillion / as.numeric(dayselapsed) ) %>% subset(select = c(, , , )) DailySpread\(dailyspread[is.na(DailySpread\)dailyspread)] <- 0 DailySpread\(dailyspreadpermillion[is.na(DailySpread\)dailyspreadpermillion)] <- 0 DailySpread

rr COVIDFinal <- left_join(COVIDGrowth, DailySpread, by = c())

rr COVIDFinal

Data Visualization

Overall Growth of COVID-19 Over Time

rr COVIDFinal %>% group_by(date) %>% summarise(totalcases = sum(cases)) %>% ggplot(aes(x = date, y = totalcases)) + geom_point() + xlab() + ylab(-19 Cases)

This graph shows the exponential growth trend that we already knew existed with COVID-19. This confirms that our data is valid in that it accurately represents the trends that have been described by researchers and scientists in the media.

Continental Growth of COVID-19 Over Time

rr na.omit(COVIDFinal) %>% group_by(date, continent) %>% summarise(totalcases = sum(cases)) %>% ggplot(aes(x = date, y = totalcases)) + geom_point() + facet_wrap(~continent) + xlab() + ylab(-19 Cases)

This graph shows the growth in cases by continent. The trend is much stronger in the origin continent of Asia, but also shows strength growing in Europe, Africa, North America, and South America.

Infection of COVID-19 into countries over time

rr na.omit(FirstInstance) %>% ggplot(aes(x = beginningofspread, fill = continent)) + geom_dotplot(stackgroups = TRUE, binwidth = 1, binpositions=) + xlab(’s First Case of COVID-19) + theme(panel.background = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.title.y = element_blank())

This graph shows the progression of the COVID-19 spread across continents. Asia was obviously the first country to have cases, but North America and Europe quickyl followed. South America and Africa both joined in late February, whereas Australia was able to isolate themselves until mid to late March.

Which countries have the highest infection rates?

rr

COVIDFinal %>% group_by(country) %>% summarise(dailyspread = mean(dailyspread)) %>% arrange(desc(dailyspread)) %>% head(20) %>% ggplot(aes(x = reorder(country, desc(dailyspread)), y= dailyspread)) + geom_bar(stat=, position = ‘stack’, width=.9) + theme(axis.text.x=element_text(angle = 60, hjust = 1)) + scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) + ylab(Number Infected Per Day) + theme(axis.title.x = element_blank())

According to this graph, the countries with the top four infection rates are China, India, Indonesia, and the United States, closely followed by Brazil. Keep in mind that this is adjusted for the population, so in this graph, population is not a confounding factor. ### Compare this to which countries have the highest populations

rr COVIDFinal %>% group_by(country) %>% summarise(pop = mean(pop)) %>% arrange(desc(pop)) %>% head(20) %>% ggplot(aes(x = reorder(country, desc(pop)), y= pop)) + geom_bar(stat=, position = ‘stack’, width=.9) + theme(axis.text.x=element_text(angle = 60, hjust = 1)) + scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) + ylab() + theme(axis.title.x = element_blank())

We see a similar trend here, in that the top four (in slightly different order) consist of China, India, Indonesia, the United States, and closely trailing Brazil.

Let’s visualize the relationship between population and COVID-19 spread on the same data frame… with an awareness of the continental distribution

rr na.omit(COVIDFinal) %>% ggplot(aes(x = pop, y = dailyspread, color = continent)) + geom_point() + xlab(of Country) + ylab(Number Infected Per Day)

Here, we can see again the trend that was represented in the two previous graphs, but now they are all in the same data frame. While most of the rest of the world trails with under 10,000 infected per day, the 5 countries with the highest popualtion in the data set have over 15,000 - up to over 50,000- and are far separated from the rest of the pack. Population, while not a direct factor contributing to the level of development of a country, is a decent indicator of the rate of infection.

Does the relationship hold up after removing the largest outliers (China and India)?

Does the positive relationship hold up across all continents?

rr na.omit(COVIDFinal) %>% ggplot(aes(x = pop, y = dailyspread, color = continent)) + geom_point() + xlim(0,500000000) + ylim(0, 40000) + xlab(of Country) + ylab(Number Infected Per Day) + stat_smooth(method = lm)

A prevailing explanation for the spread of COVID-19 is social closeness, therefore, we hypothesize that countries with the highest population density will have the highest proportional rates of infection. To measure the proportional rates of infection, it is essential to use a standardized metric, such that the data is not skewed towards the countries with simply the most people. Therefore, we will analyze the variable “population per million infected per day”, which captures a representation of the percentage of a country’s population that is effective. If our hypothesis is correct, the countries with the highest population per million infected per day will be those with the highest population density.

Which countries have the highest infection rates per million?

rr

COVIDFinal %>% group_by(country) %>% summarise(dailyspreadpermillion = mean(dailyspreadpermillion)) %>% arrange(desc(dailyspreadpermillion)) %>% head(20) %>% ggplot(aes(x = reorder(country, desc(dailyspreadpermillion)), y= dailyspreadpermillion)) + geom_bar(stat=, position = ‘stack’, width=.9) + theme(axis.text.x=element_text(angle = 60, hjust = 1)) + scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) + ylab(Per Million Infected Per Day) + theme(axis.title.x = element_blank())

Which countries have the highest population density?

rr

COVIDFinal %>% group_by(country) %>% summarise(popdensity = mean(popdensity)) %>% arrange(desc(popdensity)) %>% head(20) %>% ggplot(aes(x = reorder(country, desc(popdensity)), y= popdensity)) + geom_bar(stat=, position = ‘stack’, width=.9) + theme(axis.text.x=element_text(angle = 60, hjust = 1)) + scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) + ylab(Density (people/sq km)) + theme(axis.title.x = element_blank())

Is there a visible correlation between these attributes?

rr na.omit(COVIDFinal) %>% ggplot(aes(x = popdensity, y = dailyspreadpermillion)) + geom_point()

What if faceted by continent?

rr na.omit(COVIDFinal) %>% ggplot(aes(x = popdensity, y = dailyspreadpermillion)) + geom_point() + facet_wrap(~continent) + xlim(0,1500)

Conclusion

evelyn pls write a conclusion here… something about there being a correlation btwn population and spread, but once standardized, the correlation is far less evident… we can not prove a correlation between population density and infection rate/million.

also i defined this function (because we need a user defined function and to use wide/narrow form), but unsure exactly where to put it,, lmk if u think of a good place.

Country Comparison Function

Easy to Traverse– Wide Countries

rr WideCountries <- COVIDFinal %>% subset(select = c(,

)) %>% spread(key = date, value = cases) WideCountries[is.na(WideCountries)] <- 0 WideCountries

compareCOVID() definition

rr compareCOVID <- function(countryA, countryB) {

A <-
WideCountries %>%
filter(country == countryA)

B <- WideCountries %>% filter(country == countryB) A <- A %>% gather(key = date, value = count) %>% filter(row_number() > 1) %>% mutate(date = lubridate::ymd(date)) %>% mutate(count = as.numeric(count)) %>% mutate(country = countryA)

B <- B %>% gather(key = date, value = count) %>% filter(row_number() > 1) %>% mutate(date = lubridate::ymd(date))%>% mutate(count = as.numeric(count)) %>% mutate(country = countryB)

GG <- rbind(A,B)

return( ggplot(GG, aes(x = date, y = count, color = country)) + stat_smooth(formula = y ~ x, method = ) + ylab(of COVID-19 Cases) + xlab())

}

Ex. of compareCOVID() in use:

rr compareCOVID(, States)

rr compareCOVID(, )

rr compareCOVID(Rico, )

LS0tCnRpdGxlOiAiRmluYWwgUHJvamVjdCIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcnM6ICJKb3NlcGggUGV2bmVyIGFuZCBFdmVseW4gTXVycmF5IgotLS0KCmBgYHtyfQpsaWJyYXJ5KG1vc2FpYykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KERhdGFDb21wdXRpbmcpCmxpYnJhcnkocnZlc3QpCmxpYnJhcnkoYnJvb20pCmBgYAoKIyMgUmVzZWFyY2ggRm9jdXM6CgpBcyBDT1ZJRC0xOSBzcHJlYWRzIGF0IGFuIGFsYXJtaW5nIHJhdGUsIGEgcHJlc3NpbmcgcXVlc3Rpb24gYXQgYSBnbG9iYWwgc2NhbGUgZW1lcmdlcy0tIHdoYXQgZmFjdG9ycyBvZiBhIGNvdW50cnkgY29udHJpYnV0ZSB0byB0aGUgc3ByZWFkIG9mIENvcm9uYXZpcnVzLiBXZSBob3BlIHRvIGFuYWx5emUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgY291bnRyeSdzIHBvcHVsYXRpb24gbGV2ZWwsIHBvcHVsYXRpb24gZGVuc2l0eSwgYW5kIGNvbnRpbmVudCBjYXRlZ29yaXphdGlvbiBvbiB0aGUgc3ByZWFkIG9mIENPVklELTE5LgoKCgojIyBEYXRhIEFjY2VzcwoKIyMjIFJlYWRpbmcgaW4gdGhlIERhdGE6CgoKIyMjIyBEYXRhIFNvdXJjZSAxOiBDT1ZJRApgYGB7cn0KQ09WSUQgPC0gcmVhZC5jc3YoZmlsZSA9ICJ0b3RhbC1jb3ZpZC1jYXNlcy1kZWF0aHMtcGVyLW1pbGxpb24uY3N2IikKQ09WSUQKYGBgCgpgYGB7cn0KQ09WSUQgJT4lCiAgbnJvdygpCmBgYApgYGB7cn0KQ09WSUQgJT4lCiAgbmFtZXMoKQpgYGAKYGBge3J9CkNPVklEICU+JQogIGhlYWQoKQpgYGAKCgoKIyMjIyBEYXRhIFNvdXJjZSAyOiBDb3VudHJ5RGF0YQpgYGB7cn0KQ291bnRyeURhdGEKYGBgCgpgYGB7cn0KQ291bnRyeURhdGEgJT4lCiAgbnJvdygpCmBgYApgYGB7cn0KQ291bnRyeURhdGEgJT4lCiAgbmFtZXMoKQpgYGAKYGBge3J9CkNvdW50cnlEYXRhICU+JQogIGhlYWQoKQpgYGAKCiMjIyMgRGF0YSBTb3VyY2UgMzogY291bnRyeVJlZ2lvbnMKCmBgYHtyfQpjb3VudHJ5UmVnaW9ucwpgYGAKYGBge3J9CmNvdW50cnlSZWdpb25zICU+JQogIG5yb3coKQpgYGAKYGBge3J9CmNvdW50cnlSZWdpb25zICU+JQogIG5hbWVzKCkKYGBgCmBgYHtyfQpjb3VudHJ5UmVnaW9ucyAlPiUKICBoZWFkKCkKYGBgCgoKCgojIyBEYXRhIFdyYW5nbGluZwoKIyMjIFRpZHlpbmcgdGhlIENPVklEIERhdGFzZXQKCmBgYHtyfQpDT1ZJRApgYGAKClNpbmNlIG91ciBhbmFseXNpcyBpcyBmb2N1c2VkIG9uIHRoZSBzcHJlYWQgb2YgQ09WSUQtMTksIHdlIHNlbGVjdCBvbmx5IGNvbHVtbnMgd2hpY2ggcGVydGFpbiB0byB0aGUgbnVtYmVyIG9mIENPVklELTE5IGNhc2VzIGluIGNvdW50cmllcyBvdmVyIHRpbWUuCgpgYGB7cn0KVGlkeUNPVklEIDwtIENPVklEICU+JQogIHJlbmFtZShjb3VudHJ5ID0gdG90YWwuY292aWQuY2FzZXMuZGVhdGhzLnBlci5taWxsaW9uICkgJT4lCiAgcmVuYW1lKCBDb2RlID0gWCApICU+JQogIHJlbmFtZShkYXRlID0gWC4xICkgJT4lCiAgcmVuYW1lKGNhc2VzUGVyTWlsbGlvbiA9IFguMykgJT4lCiAgZmlsdGVyKHJvd19udW1iZXIoKSA+IDEpICU+JQogIHN1YnNldChzZWxlY3QgPSBjKDEsMiwzLDUpKSAlPiUKICBtdXRhdGUoIGNvdW50cnkgPSBhcy5jaGFyYWN0ZXIoY291bnRyeSkgKSAlPiUKICBtdXRhdGUoZGF0ZSA9IG1keShkYXRlKSkgJT4lCiAgbXV0YXRlKGNhc2VzUGVyTWlsbGlvbiA9IGFzLmludGVnZXIoY2FzZXNQZXJNaWxsaW9uKSAtIDEpCgoKYGBgCgoKYGBge3J9ClRpZHlDT1ZJRAoKYGBgCgoKCkVWRUxZTiBwbHMgZXhwbGFpbiB3aGF0IGFuIGluc3RhbmNlIHJlcHJlc2VudHMKCgojIyMgV3JhbmdsaW5nIG9mIGNvdW50cnlSZWdpb25zIERhdGFzZXQKCldlIHdpbGwgZXh0cmFjdCB0aGUgSVNPMyBjb3VudHJ5IGNvZGUgYW5kIGNvbnRpbmVudCBmcm9tIHRoZSBjb3VudHJ5UmVnaW9ucyBkYXRhLiBTaW5jZSBuYW1pbmcgY29udmVudGlvbnMgb2YgY291bnRyaWVzIGlzIHZhcmlhdGUsIHRoZSBJU08zIGNvdW50cnkgY29kZSBhbGxvd3MgdXMgYSBzdGFuZGFyZGl6ZWQgZGVtYXJjYXRpb24gb2YgY291bnRyeSB3aXRoIHdoaWNoIHRvIGpvaW4gd2l0aCBvdGhlciBkYXRhIHRhYmxlcy4KCmBgYHtyfQpMYWJlbHMgPC0KICBjb3VudHJ5UmVnaW9ucyAlPiUKICBzdWJzZXQoc2VsZWN0ID0gYygiSVNPMyIsICJSRUdJT04iKSkgJT4lCiAgcmVuYW1lKGNvbnRpbmVudCA9IFJFR0lPTikKCkxhYmVscwoKYGBgCgoKIyMjIERhdGEgRXh0cmFjdGlvbiBvZiBDb3VudHJ5RGF0YSBEYXRhc2V0CgpXZSB3aWxsIHNlbGVjdCB0aGUgYXNwZWN0cyBvZiBDb3VudHJ5RGF0YSByZWxldmFudCB0byBvdXIgYW5hbHlzaXMuIFRoZXNlIGF0dHJpYnV0ZXMgYXJlOiBhcmVhIChzcSBrbSkgYW5kIHBvcCAobnVtYmVyIG9mIHBlb3BsZSkuCgpgYGB7cn0KClJlbGV2YW50Q291bnRyeURhdGEgPC0KICBDb3VudHJ5RGF0YSAlPiUKICBzdWJzZXQoc2VsZWN0ID0gYygxLDIsMykpICU+JQogIG11dGF0ZShwb3BkZW5zaXR5ID0gcG9wL2FyZWEpCgpSZWxldmFudENvdW50cnlEYXRhCmBgYAoKIyMjIEpvaW5pbmcgRGF0YSAmIFJlbGV2YW50IFZhcmlhYmxlIFN5bnRoZXNpcwoKQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgY2FzZXMgaW4gZWFjaCBjb3VudHJ5IGJ5IG11bHRpcGx5aW5nIGNhc2VzUGVyTWlsbGlvbiBieSB0aGUgY291bnRyeSdzIHBvcHVsYXRpb24gKGluIG1pbGxpb25zKS4gCmBgYHtyfQoKQ09WSURHcm93dGggPC0KICBpbm5lcl9qb2luKFRpZHlDT1ZJRCwgUmVsZXZhbnRDb3VudHJ5RGF0YSwgYnkgPSBjKCJjb3VudHJ5IikpICU+JQogIG11dGF0ZSgiY2FzZXMiID0gKGNhc2VzUGVyTWlsbGlvbiAqIHJvdW5kKHBvcC8xMDAwMDAwLCBkaWdpdHMgPSAwKSkpCgpDT1ZJREdyb3d0aCA8LQogIENPVklER3Jvd3RoICU+JQogIGxlZnRfam9pbihMYWJlbHMsIGJ5ID0gYygiQ29kZSIgPSAiSVNPMyIpKQoKQ09WSURHcm93dGgKYGBgCgojIyMgQ3JlYXRpb24gb2YgbmV3IERhdGEgVGFibGU6IEZpcnN0SW5zdGFuY2UKClRoaXMgdGFibGUgcmVjb3JkcyB0aGUgZmlyc3QgZGF0ZSB0aGF0IGEgY291bnRyeSByZWNvcmRlZCBhIG5vbnplcm8gbnVtYmVyIG9mIENPVklELTE5IGNhc2VzLiBUaGlzIGRhdGFncmFwaCB3aWxsIGhlbHAgdXMgdmlzdWFsaXplIHdoZW4gY291bnRyaWVzIGZpcnN0IGJlY2FtZSBpbmZlY3RlZC4KYGBge3J9CgpGaXJzdEluc3RhbmNlIDwtCiAgQ09WSURHcm93dGggJT4lCiAgZmlsdGVyKGNhc2VzICE9IDApICU+JQogIGdyb3VwX2J5KGNvdW50cnksIGNvbnRpbmVudCkgJT4lCiAgc3VtbWFyaXNlKGJlZ2lubmluZ29mc3ByZWFkID0gbWluKGRhdGUpKQogIApGaXJzdEluc3RhbmNlCgoKYGBgCgoKCgpUaGlzIHRhYmxlIGF2ZXJhZ2VzIHRoZSBudW1iZXIgb2YgY2FzZSBpbmNyZWFzZSBwZXIgZGF5IGZyb20gdGhlIGZpcnN0IGRheSBhIGNvdW50cnkgaGFkIENPVklELTE5IHRvIHRoZSBtb3N0IHJlY2VudCBpbiB0aGUgZGF0YSB0YWJsZSAoQXByaWwgNSAyMDIwKQoKYGBge3J9CgpEYWlseVNwcmVhZCA8LQogIGxlZnRfam9pbihDT1ZJREdyb3d0aCwgRmlyc3RJbnN0YW5jZSwgYnkgPSBjKCJjb3VudHJ5IikpICU+JQogIGZpbHRlcihkYXRlID09ICIyMDIwLTA0LTA1IikgJT4lCiAgbXV0YXRlKGRheXNlbGFwc2VkID0gZGF0ZSAtIGJlZ2lubmluZ29mc3ByZWFkKSAlPiUKICBtdXRhdGUoZGFpbHlzcHJlYWQgPSBjYXNlcyAvIGFzLm51bWVyaWMoZGF5c2VsYXBzZWQpICkgJT4lCiAgbXV0YXRlKGRhaWx5c3ByZWFkcGVybWlsbGlvbiA9IGNhc2VzUGVyTWlsbGlvbiAvIGFzLm51bWVyaWMoZGF5c2VsYXBzZWQpICkgJT4lCiAgc3Vic2V0KHNlbGVjdCA9IGMoImNvdW50cnkiLCAiYmVnaW5uaW5nb2ZzcHJlYWQiLCAiZGFpbHlzcHJlYWQiLCAiZGFpbHlzcHJlYWRwZXJtaWxsaW9uIikpCgpEYWlseVNwcmVhZCRkYWlseXNwcmVhZFtpcy5uYShEYWlseVNwcmVhZCRkYWlseXNwcmVhZCldIDwtIDAKRGFpbHlTcHJlYWQkZGFpbHlzcHJlYWRwZXJtaWxsaW9uW2lzLm5hKERhaWx5U3ByZWFkJGRhaWx5c3ByZWFkcGVybWlsbGlvbildIDwtIDAKCgpEYWlseVNwcmVhZApgYGAKCgoKYGBge3J9CgpDT1ZJREZpbmFsIDwtCiAgbGVmdF9qb2luKENPVklER3Jvd3RoLCBEYWlseVNwcmVhZCwgYnkgPSBjKCJjb3VudHJ5IikpCgoKYGBgCgoKCmBgYHtyfQpDT1ZJREZpbmFsCgpgYGAKCgoKCgoKCgojIyBEYXRhIFZpc3VhbGl6YXRpb24KCgojIyMgT3ZlcmFsbCBHcm93dGggb2YgQ09WSUQtMTkgT3ZlciBUaW1lCmBgYHtyfQoKQ09WSURGaW5hbCAlPiUKICBncm91cF9ieShkYXRlKSAlPiUKICBzdW1tYXJpc2UodG90YWxjYXNlcyA9IHN1bShjYXNlcykpICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSB0b3RhbGNhc2VzKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkRhdGUiKSArCiAgeWxhYigiQ09WSUQtMTkgQ2FzZXMiKQoKYGBgClRoaXMgZ3JhcGggc2hvd3MgdGhlIGV4cG9uZW50aWFsIGdyb3d0aCB0cmVuZCB0aGF0IHdlIGFscmVhZHkga25ldyBleGlzdGVkIHdpdGggQ09WSUQtMTkuICBUaGlzIGNvbmZpcm1zIHRoYXQgb3VyIGRhdGEgaXMgdmFsaWQgaW4gdGhhdCBpdCBhY2N1cmF0ZWx5IHJlcHJlc2VudHMgdGhlIHRyZW5kcyB0aGF0IGhhdmUgYmVlbiBkZXNjcmliZWQgYnkgcmVzZWFyY2hlcnMgYW5kIHNjaWVudGlzdHMgaW4gdGhlIG1lZGlhLgoKCgojIyMgQ29udGluZW50YWwgR3Jvd3RoIG9mIENPVklELTE5IE92ZXIgVGltZQoKYGBge3J9CgpuYS5vbWl0KENPVklERmluYWwpICU+JQogIGdyb3VwX2J5KGRhdGUsIGNvbnRpbmVudCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gdG90YWxjYXNlcykpICsgCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF93cmFwKH5jb250aW5lbnQpICsKICB4bGFiKCJEYXRlIikgKwogIHlsYWIoIkNPVklELTE5IENhc2VzIikKYGBgClRoaXMgZ3JhcGggc2hvd3MgdGhlIGdyb3d0aCBpbiBjYXNlcyBieSBjb250aW5lbnQuICBUaGUgdHJlbmQgaXMgbXVjaCBzdHJvbmdlciBpbiB0aGUgb3JpZ2luIGNvbnRpbmVudCBvZiBBc2lhLCBidXQgYWxzbyBzaG93cyBzdHJlbmd0aCBncm93aW5nIGluIEV1cm9wZSwgQWZyaWNhLCBOb3J0aCBBbWVyaWNhLCBhbmQgU291dGggQW1lcmljYS4KCiMjIyBJbmZlY3Rpb24gb2YgQ09WSUQtMTkgaW50byBjb3VudHJpZXMgb3ZlciB0aW1lCmBgYHtyfQoKbmEub21pdChGaXJzdEluc3RhbmNlKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBiZWdpbm5pbmdvZnNwcmVhZCwgZmlsbCA9IGNvbnRpbmVudCkpICsKICBnZW9tX2RvdHBsb3Qoc3RhY2tncm91cHMgPSBUUlVFLCBiaW53aWR0aCA9IDEsIGJpbnBvc2l0aW9ucz0iYWxsIikgKwogIHhsYWIoIkNvdW50cnkncyBGaXJzdCBDYXNlIG9mIENPVklELTE5IikgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgClRoaXMgZ3JhcGggc2hvd3MgdGhlIHByb2dyZXNzaW9uIG9mIHRoZSBDT1ZJRC0xOSBzcHJlYWQgYWNyb3NzIGNvbnRpbmVudHMuIEFzaWEgd2FzIG9idmlvdXNseSB0aGUgZmlyc3QgY291bnRyeSB0byBoYXZlIGNhc2VzLCBidXQgTm9ydGggQW1lcmljYSBhbmQgRXVyb3BlIHF1aWNreWwgZm9sbG93ZWQuICBTb3V0aCBBbWVyaWNhIGFuZCBBZnJpY2EgYm90aCBqb2luZWQgaW4gbGF0ZSBGZWJydWFyeSwgd2hlcmVhcyBBdXN0cmFsaWEgd2FzIGFibGUgdG8gaXNvbGF0ZSB0aGVtc2VsdmVzIHVudGlsIG1pZCB0byBsYXRlIE1hcmNoLgoKCgoKIyMjIFdoaWNoIGNvdW50cmllcyBoYXZlIHRoZSBoaWdoZXN0IGluZmVjdGlvbiByYXRlcz8KCgpgYGB7cn0KICAKQ09WSURGaW5hbCAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBzdW1tYXJpc2UoZGFpbHlzcHJlYWQgPSBtZWFuKGRhaWx5c3ByZWFkKSkgJT4lCiAgYXJyYW5nZShkZXNjKGRhaWx5c3ByZWFkKSkgJT4lCiAgaGVhZCgyMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCBkZXNjKGRhaWx5c3ByZWFkKSksIHk9IGRhaWx5c3ByZWFkKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAnc3RhY2snLCB3aWR0aD0uOSkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKSArCiAgeWxhYigiQXZlcmFnZSBOdW1iZXIgSW5mZWN0ZWQgUGVyIERheSIpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCgoKCmBgYApBY2NvcmRpbmcgdG8gdGhpcyBncmFwaCwgdGhlIGNvdW50cmllcyB3aXRoIHRoZSB0b3AgZm91ciBpbmZlY3Rpb24gcmF0ZXMgYXJlIENoaW5hLCBJbmRpYSwgSW5kb25lc2lhLCBhbmQgdGhlIFVuaXRlZCBTdGF0ZXMsIGNsb3NlbHkgZm9sbG93ZWQgYnkgQnJhemlsLiAgS2VlcCBpbiBtaW5kIHRoYXQgdGhpcyBpcyBhZGp1c3RlZCBmb3IgdGhlIHBvcHVsYXRpb24sIHNvIGluIHRoaXMgZ3JhcGgsIHBvcHVsYXRpb24gaXMgbm90IGEgY29uZm91bmRpbmcgZmFjdG9yLgojIyMgQ29tcGFyZSB0aGlzIHRvIHdoaWNoIGNvdW50cmllcyBoYXZlIHRoZSBoaWdoZXN0IHBvcHVsYXRpb25zCgpgYGB7cn0KCkNPVklERmluYWwgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lCiAgc3VtbWFyaXNlKHBvcCA9IG1lYW4ocG9wKSkgJT4lCiAgYXJyYW5nZShkZXNjKHBvcCkpICU+JQogIGhlYWQoMjApICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoY291bnRyeSwgZGVzYyhwb3ApKSwgeT0gcG9wKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAnc3RhY2snLCB3aWR0aD0uOSkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKSArCiAgeWxhYigiUG9wdWxhdGlvbiIpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCgoKYGBgCldlIHNlZSBhIHNpbWlsYXIgdHJlbmQgaGVyZSwgaW4gdGhhdCB0aGUgdG9wIGZvdXIgKGluIHNsaWdodGx5IGRpZmZlcmVudCBvcmRlcikgY29uc2lzdCBvZiBDaGluYSwgSW5kaWEsIEluZG9uZXNpYSwgdGhlIFVuaXRlZCBTdGF0ZXMsIGFuZCBjbG9zZWx5IHRyYWlsaW5nIEJyYXppbC4KCiMjIyBMZXQncyB2aXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHBvcHVsYXRpb24gYW5kIENPVklELTE5IHNwcmVhZCBvbiB0aGUgc2FtZSBkYXRhIGZyYW1lLi4uIHdpdGggYW4gYXdhcmVuZXNzIG9mIHRoZSBjb250aW5lbnRhbCBkaXN0cmlidXRpb24KCgpgYGB7cn0KCm5hLm9taXQoQ09WSURGaW5hbCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcG9wLCB5ID0gZGFpbHlzcHJlYWQsIGNvbG9yID0gY29udGluZW50KSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIlBvcHVsYXRpb24gb2YgQ291bnRyeSIpICsKICB5bGFiKCJBdmVyYWdlIE51bWJlciBJbmZlY3RlZCBQZXIgRGF5IikKCgoKYGBgCkhlcmUsIHdlIGNhbiBzZWUgYWdhaW4gdGhlIHRyZW5kIHRoYXQgd2FzIHJlcHJlc2VudGVkIGluIHRoZSB0d28gcHJldmlvdXMgZ3JhcGhzLCBidXQgbm93IHRoZXkgYXJlIGFsbCBpbiB0aGUgc2FtZSBkYXRhIGZyYW1lLiAgV2hpbGUgbW9zdCBvZiB0aGUgcmVzdCBvZiB0aGUgd29ybGQgdHJhaWxzIHdpdGggdW5kZXIgMTAsMDAwIGluZmVjdGVkIHBlciBkYXksIHRoZSA1IGNvdW50cmllcyB3aXRoIHRoZSBoaWdoZXN0IHBvcHVhbHRpb24gaW4gdGhlIGRhdGEgc2V0IGhhdmUgb3ZlciAxNSwwMDAgLSB1cCB0byBvdmVyIDUwLDAwMC0gYW5kIGFyZSBmYXIgc2VwYXJhdGVkIGZyb20gdGhlIHJlc3Qgb2YgdGhlIHBhY2suICBQb3B1bGF0aW9uLCB3aGlsZSBub3QgYSBkaXJlY3QgZmFjdG9yIGNvbnRyaWJ1dGluZyB0byB0aGUgbGV2ZWwgb2YgZGV2ZWxvcG1lbnQgb2YgYSBjb3VudHJ5LCBpcyBhIGRlY2VudCBpbmRpY2F0b3Igb2YgdGhlIHJhdGUgb2YgaW5mZWN0aW9uLgoKCiMjIyBEb2VzIHRoZSByZWxhdGlvbnNoaXAgaG9sZCB1cCBhZnRlciByZW1vdmluZyB0aGUgbGFyZ2VzdCBvdXRsaWVycyAoQ2hpbmEgYW5kIEluZGlhKT8KIyMjIERvZXMgdGhlIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBob2xkIHVwIGFjcm9zcyBhbGwgY29udGluZW50cz8KYGBge3J9CgpuYS5vbWl0KENPVklERmluYWwpICU+JQogIGdncGxvdChhZXMoeCA9IHBvcCwgeSA9IGRhaWx5c3ByZWFkLCBjb2xvciA9IGNvbnRpbmVudCkpICsgCiAgZ2VvbV9wb2ludCgpICsKICB4bGltKDAsNTAwMDAwMDAwKSArCiAgeWxpbSgwLCA0MDAwMCkgKwogIHhsYWIoIlBvcHVsYXRpb24gb2YgQ291bnRyeSIpICsKICB5bGFiKCJBdmVyYWdlIE51bWJlciBJbmZlY3RlZCBQZXIgRGF5IikgKwogIHN0YXRfc21vb3RoKG1ldGhvZCA9IGxtKSAKCgoKYGBgCgoKCiMjIyBBIHByZXZhaWxpbmcgZXhwbGFuYXRpb24gZm9yIHRoZSBzcHJlYWQgb2YgQ09WSUQtMTkgaXMgc29jaWFsIGNsb3NlbmVzcywgdGhlcmVmb3JlLCB3ZSBoeXBvdGhlc2l6ZSB0aGF0IGNvdW50cmllcyB3aXRoIHRoZSBoaWdoZXN0IHBvcHVsYXRpb24gZGVuc2l0eSB3aWxsIGhhdmUgdGhlIGhpZ2hlc3QgcHJvcG9ydGlvbmFsIHJhdGVzIG9mIGluZmVjdGlvbi4gVG8gbWVhc3VyZSB0aGUgcHJvcG9ydGlvbmFsIHJhdGVzIG9mIGluZmVjdGlvbiwgaXQgaXMgZXNzZW50aWFsIHRvIHVzZSBhIHN0YW5kYXJkaXplZCBtZXRyaWMsIHN1Y2ggdGhhdCB0aGUgZGF0YSBpcyBub3Qgc2tld2VkIHRvd2FyZHMgdGhlIGNvdW50cmllcyB3aXRoIHNpbXBseSB0aGUgbW9zdCBwZW9wbGUuIFRoZXJlZm9yZSwgd2Ugd2lsbCBhbmFseXplIHRoZSB2YXJpYWJsZSAicG9wdWxhdGlvbiBwZXIgbWlsbGlvbiBpbmZlY3RlZCBwZXIgZGF5Iiwgd2hpY2ggY2FwdHVyZXMgYSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGVyY2VudGFnZSBvZiBhIGNvdW50cnkncyBwb3B1bGF0aW9uIHRoYXQgaXMgZWZmZWN0aXZlLiBJZiBvdXIgaHlwb3RoZXNpcyBpcyBjb3JyZWN0LCB0aGUgY291bnRyaWVzIHdpdGggdGhlIGhpZ2hlc3QgcG9wdWxhdGlvbiBwZXIgbWlsbGlvbiBpbmZlY3RlZCBwZXIgZGF5IHdpbGwgYmUgdGhvc2Ugd2l0aCB0aGUgaGlnaGVzdCBwb3B1bGF0aW9uIGRlbnNpdHkuCgoKIyMjIFdoaWNoIGNvdW50cmllcyBoYXZlIHRoZSBoaWdoZXN0IGluZmVjdGlvbiByYXRlcyBwZXIgbWlsbGlvbj8KCgpgYGB7cn0KICAKQ09WSURGaW5hbCAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBzdW1tYXJpc2UoZGFpbHlzcHJlYWRwZXJtaWxsaW9uID0gbWVhbihkYWlseXNwcmVhZHBlcm1pbGxpb24pKSAlPiUKICBhcnJhbmdlKGRlc2MoZGFpbHlzcHJlYWRwZXJtaWxsaW9uKSkgJT4lCiAgaGVhZCgyMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCBkZXNjKGRhaWx5c3ByZWFkcGVybWlsbGlvbikpLCB5PSBkYWlseXNwcmVhZHBlcm1pbGxpb24pKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICdzdGFjaycsIHdpZHRoPS45KSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIGhqdXN0ID0gMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBGQUxTRSkpICsKICB5bGFiKCJQb3B1bGF0aW9uIFBlciBNaWxsaW9uIEluZmVjdGVkIFBlciBEYXkiKSArCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQoKCgpgYGAKCiMjIyBXaGljaCBjb3VudHJpZXMgaGF2ZSB0aGUgaGlnaGVzdCBwb3B1bGF0aW9uIGRlbnNpdHk/CgpgYGB7cn0KICAKQ09WSURGaW5hbCAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBzdW1tYXJpc2UocG9wZGVuc2l0eSA9IG1lYW4ocG9wZGVuc2l0eSkpICU+JQogIGFycmFuZ2UoZGVzYyhwb3BkZW5zaXR5KSkgJT4lCiAgaGVhZCgyMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCBkZXNjKHBvcGRlbnNpdHkpKSwgeT0gcG9wZGVuc2l0eSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gJ3N0YWNrJywgd2lkdGg9LjkpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGUgPSA2MCwgaGp1c3QgPSAxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IEZBTFNFKSkgKwogIHlsYWIoIlBvcHVsYXRpb24gRGVuc2l0eSAocGVvcGxlL3NxIGttKSIpICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCgoKCmBgYAoKCgoKIyMjIElzIHRoZXJlIGEgdmlzaWJsZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZXNlIGF0dHJpYnV0ZXM/CgoKYGBge3J9Cm5hLm9taXQoQ09WSURGaW5hbCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcG9wZGVuc2l0eSwgeSA9IGRhaWx5c3ByZWFkcGVybWlsbGlvbikpICsKICBnZW9tX3BvaW50KCkgCmBgYAoKCiMjIyBXaGF0IGlmIGZhY2V0ZWQgYnkgY29udGluZW50PwoKYGBge3J9Cm5hLm9taXQoQ09WSURGaW5hbCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcG9wZGVuc2l0eSwgeSA9IGRhaWx5c3ByZWFkcGVybWlsbGlvbikpICsKICBnZW9tX3BvaW50KCkgKyAKICBmYWNldF93cmFwKH5jb250aW5lbnQpICsgCiAgeGxpbSgwLDE1MDApCgpgYGAKCgoKCgoKIyMgQ29uY2x1c2lvbgoKCgpldmVseW4gcGxzIHdyaXRlIGEgY29uY2x1c2lvbiBoZXJlLi4uIHNvbWV0aGluZyBhYm91dCB0aGVyZSBiZWluZyBhIGNvcnJlbGF0aW9uIGJ0d24gcG9wdWxhdGlvbiBhbmQgc3ByZWFkLCBidXQgb25jZSBzdGFuZGFyZGl6ZWQsIHRoZSBjb3JyZWxhdGlvbiBpcyBmYXIgbGVzcyBldmlkZW50Li4uIHdlIGNhbiBub3QgcHJvdmUgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBvcHVsYXRpb24gZGVuc2l0eSBhbmQgaW5mZWN0aW9uIHJhdGUvbWlsbGlvbi4KCgphbHNvIGkgZGVmaW5lZCB0aGlzIGZ1bmN0aW9uIChiZWNhdXNlIHdlIG5lZWQgYSB1c2VyIGRlZmluZWQgZnVuY3Rpb24gYW5kIHRvIHVzZSB3aWRlL25hcnJvdyBmb3JtKSwgYnV0IHVuc3VyZSBleGFjdGx5IHdoZXJlIHRvIHB1dCBpdCwsIGxtayBpZiB1IHRoaW5rIG9mIGEgZ29vZCBwbGFjZS4KCgoKCgojIyBDb3VudHJ5IENvbXBhcmlzb24gRnVuY3Rpb24KCgojIyMgRWFzeSB0byBUcmF2ZXJzZS0tIFdpZGUgQ291bnRyaWVzCgpgYGB7cn0KCldpZGVDb3VudHJpZXMgPC0KICBDT1ZJREZpbmFsICU+JQogIHN1YnNldChzZWxlY3QgPSBjKCJjb3VudHJ5IiwgImRhdGUiLCAiY2FzZXMiKSkgJT4lCiAgc3ByZWFkKGtleSA9IGRhdGUsIHZhbHVlID0gY2FzZXMpCgpXaWRlQ291bnRyaWVzW2lzLm5hKFdpZGVDb3VudHJpZXMpXSA8LSAwCgpXaWRlQ291bnRyaWVzCgpgYGAKCiMjIyBjb21wYXJlQ09WSUQoKSBkZWZpbml0aW9uCgpgYGB7cn0KCmNvbXBhcmVDT1ZJRCA8LSBmdW5jdGlvbihjb3VudHJ5QSwgY291bnRyeUIpIHsKICAKICAgIEEgPC0KICAgIFdpZGVDb3VudHJpZXMgJT4lCiAgICBmaWx0ZXIoY291bnRyeSA9PSBjb3VudHJ5QSkKICAKICBCIDwtCiAgICBXaWRlQ291bnRyaWVzICU+JQogICAgZmlsdGVyKGNvdW50cnkgPT0gY291bnRyeUIpCgogIEEgPC0KICAgIEEgJT4lCiAgICBnYXRoZXIoa2V5ID0gZGF0ZSwgdmFsdWUgPSBjb3VudCkgJT4lCiAgICBmaWx0ZXIocm93X251bWJlcigpID4gMSkgJT4lCiAgICBtdXRhdGUoZGF0ZSA9IGx1YnJpZGF0ZTo6eW1kKGRhdGUpKSAlPiUKICAgIG11dGF0ZShjb3VudCA9IGFzLm51bWVyaWMoY291bnQpKSAlPiUKICAgIG11dGF0ZShjb3VudHJ5ID0gY291bnRyeUEpCiAgCiAgQiA8LQogICAgQiAlPiUKICAgIGdhdGhlcihrZXkgPSBkYXRlLCB2YWx1ZSA9IGNvdW50KSAlPiUKICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgPiAxKSAlPiUKICAgIG11dGF0ZShkYXRlID0gbHVicmlkYXRlOjp5bWQoZGF0ZSkpJT4lCiAgICBtdXRhdGUoY291bnQgPSBhcy5udW1lcmljKGNvdW50KSkgJT4lCiAgICBtdXRhdGUoY291bnRyeSA9IGNvdW50cnlCKQogIAogIAogIEdHIDwtCiAgICByYmluZChBLEIpCiAgCiAgcmV0dXJuKCBnZ3Bsb3QoR0csIGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50LCBjb2xvciA9IGNvdW50cnkpKSArCiAgICBzdGF0X3Ntb290aChmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsb2VzcyIpICsKICAgICAgeWxhYigiTnVtYmVyIG9mIENPVklELTE5IENhc2VzIikgKwogICAgICB4bGFiKCJEYXRlIikpCiAgCn0KCgoKCmBgYAoKCiMjIyBFeC4gb2YgY29tcGFyZUNPVklEKCkgaW4gdXNlOgoKYGBge3J9Cgpjb21wYXJlQ09WSUQoIkNoaW5hIiwgIlVuaXRlZCBTdGF0ZXMiKQoKY29tcGFyZUNPVklEKCJKYXBhbiIsICJSdXNzaWEiKQoKY29tcGFyZUNPVklEKCJQdWVydG8gUmljbyIsICJCZWxnaXVtIikKCmBgYAoKCgo=